#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include<mutex>
#include<thread>
#include<vector>

// 只能在堆上创建的对象
class HeapOnly
{
public:
	static HeapOnly* Create()
	{
		return new HeapOnly;
	}

	HeapOnly(const HeapOnly& ho) = delete;

private:
	HeapOnly()
		:_a(0)
	{}

	int _a;
};

// 只能在栈上创建对象
// 删除new
class StackOnly
{
public:
	static StackOnly Create()
	{
		return StackOnly();
	}

	void* operator new(size_t st) = delete;// 重载new，然后禁用new


private:
	StackOnly()
		:_a(0)
	{}


	int _a;

};

// 设计一个类不能被拷贝
class CopyBan
{


};

// 设计一个类不能被继承
class InheritBan final
{

};

// 设计一个类只能创建一个对象（单例模式）
// 饿汉：提前准备好，随时可以用，没有多线程安全问题，main函数之前就创建好了
// 优点：简单无线程安全问题
// 缺点：1.无法控制创建时间，比如需要在特定时间创建 2.如果单例对象很大初始化很费时间，会导致程序启动慢
// 懒汉：不提前准备，第一次使用时才创建
// 优点：解决了饿汉的缺点
// 缺点：相对复杂，需要解决多线程问题
// 简单实现一个懒汉模式(有多线程安全问题，需要加锁)
class Singleton
{
public:
	static Singleton& GetInstance()
	{
		// 双检查加锁，后续调用该函数更高效
		if (_pInst == nullptr)
		{
			unique_lock<mutex> lock(_mtx);
			if (_pInst == nullptr)
			{
				_pInst = new Singleton;
			}
		}
		return *_pInst;
	}
	
	//// 另类写法
	//static Singleton& GetInstance()
	//{
	//	// 因为static生命周期是整个程序生命周期且在该作用域下只存在一份，满足懒汉单例模式
	//	// C++98不保证static创建的线程安全
	//	// C++11可以保证static创建线程安全，所以该写法既简单又能满足懒汉模式
	//	static Singleton Inst;
	//	return Inst;
	//}

	void Add()
	{
		unique_lock<mutex> lock(_mtx);
		++_a;
	}

	int GetA()
	{
		return _a;
	}

	Singleton(const Singleton&) = delete; // 不允许拷贝

private:
	Singleton()
		:_a(0)
	{
		cout << "create()" << endl;
	}
	// 实现一个内嵌垃圾回收类
	// 一般懒汉单例对象不需要回收，因为进程结束资源都会还给系统，且这个对象只有一个，让系统回收就行
	// 但是如果在单例对象析构时，需要做一些收尾动作，比如记录日志等，就可以考虑写一个内嵌垃圾回收类
	class CGarbo
	{
	public:
		~CGarbo()
		{
			if (_pInst)
			{
				cout << "~Sigleton()1" << endl;
				delete _pInst;
				_pInst = nullptr;
			}

		}
	};

	static CGarbo cg;
	int _a;
	static mutex _mtx;
	static Singleton* _pInst;
};
// 静态变量或对象需在外面声明
Singleton* Singleton::_pInst = nullptr;
mutex Singleton::_mtx;
Singleton::CGarbo Singleton::cg;

void Test()
{
	for (int i = 0; i < 1000; ++i)
	{
		Singleton::GetInstance().Add();
	}
}

int main()
{
	StackOnly so = StackOnly::Create();
	//StackOnly* so1 = new StackOnly(so);
	cout << int(true) << endl;
	vector<thread> v(5);
	for (auto& t : v)
	{
		t = thread(Test);
	}
	for (auto& t : v)
	{
		t.join();
	}
	cout << Singleton::GetInstance().GetA() << endl;
	return 0;
}